#include "SnakerMap.h"
using namespace std;

SnakerFruit* SnakerMap::GetFruit(SnakerChunk* tar, int id) {
    return tar->fruitList[id - 1];
}

SnakerChunk::SnakerChunk(int cx, int cy) : cx(cx), cy(cy) {
    fruitList.resize(0);
    // xmin = cx * chunkSize;
    // ymin = cy * chunkSize;
    // xmax = (cx + 1) * chunkSize - 1;
    // ymax = (cy + 1) * chunkSize - 1;
    for (int i = 0; i < chunkSize; i++) {
        for (int j = 0; j < chunkSize; j++) {
            data[i][j] = (rrer.glob_rand() % 100 < 2) ? 0 : -1;
        }
    }
}

SnakerChunk* SnakerMap::mapOrigin() {
    return chunkMap[pair<int, int>(0, 0)];
}

bool SnakerMap::hasChunk(int cx, int cy) {
    return chunkMap.find(pair<int, int>(cx, cy)) != chunkMap.end();
}

SnakerChunk* SnakerMap::FindChunk(int cx, int cy) {
    if (hasChunk(cx, cy)) {
        return chunkMap[pair<int, int>(cx, cy)];
    }
    return mapOrigin();
}

bool SnakerMap::inChunk(int x, int y, SnakerChunk* chk) {
    return pair<int, int>(dim(x, chunkSize), dim(y, chunkSize)) < pair<int, int>(chk->cx + 1, chk->cy + 1) && !(pair<int, int>(dim(x, chunkSize), dim(y, chunkSize)) < pair<int, int>(chk->cx, chk->cy));
}

SnakerChunk* SnakerMap::GetChunk(int x, int y) {
    return FindChunk(dim(x, chunkSize), dim(y, chunkSize));
}

vector<SnakerFruit*> SnakerMap::ListFruit(SnakerChunk* chk) {
    return chk->fruitList;
}

void SnakerMap::GenerateFruit(SnakerChunk* chk, SnakerFruit* fruit) {
    if (ListFruit(chk).size() > chunkSize / 2) return;
    for (int i = 0; i < chunkSize; i++) {
        for (int j = 0; j < chunkSize; j++) {
            if (chk->data[i][j] == -1 && rrer.glob_rand() % 1000 < 2) AddFruit(fruit, i + chk->cx * chunkSize, j + chk->cy * chunkSize); 
        }
    }
}

// int SnakerMap::GetTerrainType(int x, int y) {
//     SnakerChunk* chk = GetChunk(x, y);
//     return chk->data[mdim(x, chunkSize)][mdim(y, chunkSize)];
// }

int SnakerMap::GetTerrainType(int x, int y, SnakerChunk* chk) {
    return chk->data[mdim(x, chunkSize)][mdim(y, chunkSize)];
}

int SnakerMap::GetTerrainType(int x, int y) {
    return GetTerrainType(x, y, GetChunk(x, y));
}

void SnakerMap::GenerateMapOrigin() {
    chunkMap.clear();
    chunkMap[pair<int, int>(0, 0)] = new SnakerChunk(0, 0);
    // chunkMap.insert(make_pair(Vector2(0, 0), new ))
}

void SnakerMap::ExpandMap(SnakerChunk* chk, bool EXP_FLG) {
    int cx = chk->cx, cy = chk->cy;
    for (int i = 0; i < 4; i++) {
        int tcx = cx + STEP[i][0], tcy = cy + STEP[i][1];
        if (!hasChunk(tcx, tcy)) {
            SnakerChunk* curChk = new SnakerChunk(tcx, tcy);
            chunkMap[pair<int, int>(tcx, tcy)] = curChk;
            if (EXP_FLG) ExpandMap(curChk, false);
        }
    }
}

void SnakerMap::AddFruit(SnakerFruit* fruit, int x, int y) {
    SnakerChunk* tarChunk = SnakerMap::GetChunk(x, y);
    int px = mdim(x, chunkSize), py = mdim(y, chunkSize);
    if (tarChunk->data[px][py]) {
        tarChunk->fruitList.push_back(fruit);
        tarChunk->bookFruitList.push_back(true);
        tarChunk->data[px][py] = tarChunk->fruitList.size();
    }
}

void SnakerMap::RemoveFruit(int x, int y) {
    SnakerChunk* tarChunk = SnakerMap::GetChunk(x, y);
    int px = mdim(x, chunkSize), py = mdim(y, chunkSize);
    if (tarChunk->data[px][py] > 0) {
        // tarChunk->fruitList.erase(tarChunk->fruitList.begin() + tarChunk->data[px][py]);
        tarChunk->bookFruitList[tarChunk->data[px][py]] = false;
        tarChunk->data[px][py] = -1;
    }
}

void SnakerMap::Init() {
    GenerateMapOrigin();
    // for (int i = 0; i < 5 * chunkSize; i++) memset(canvas + i, 0, sizeof(char) * chunkSize);
    ExpandMap(chunkMap[pair<int, int>(0, 0)]);
}

string SnakerMap::DisplayChunk(SnakerChunk* chk) {
    string res = "";
    for (int i = 0; i < chunkSize; i++) {
        for (int j = 0; j < chunkSize; j++) {
            res += (chk->data[i][j]) ? '.' : '#';
        }
        res += '\n';
    }
    return res;
}

char** SnakerMap::DisplayChunkC(SnakerChunk* chk) {
    char** res = (char**)new char*[chunkSize];
    for (int i = 0; i < chunkSize; i++) res[i] = new char[chunkSize];
    for (int i = 0; i < chunkSize; i++) {
        for (int j = 0; j < chunkSize; j++) {
            res[i][j] = (chk->data[i][j]) ? '.' : '#';
        }
    }
    return res;
}

// void SnakerMap::UpdateCanvas(int cx, int cy) {
//     ExpandMap(FindChunk(cx, cy));
//     for (int i = 0; i <= 2; i++) {
//         for (int j = 0; j <= 2; j++) {
//             SnakerChunk* chk = FindChunk(cx + i - 1, cy + j - 1);
//             for (int ii = 0; ii < chunkSize; ii++) {
//                 for (int jj = 0; jj < chunkSize; jj++) {
//                     canvas[i * chunkSize + ii][j * chunkSize + jj] = chk->data[ii][jj] ? '.' : '#';
//                 }
//             }
//         }
//     }
// }